use serde::{Deserialize, Serialize};
use crate::rpc::RpcConfig;

/// 通用应用配置
#[derive(Debug, Deserialize, Clone)]
pub struct AppConfig {
    /// 服务器配置
    pub server: ServerConfig,
    /// 数据库配置
    pub database: DatabaseConfig,
    /// Redis配置
    pub redis: RedisConfig,
    /// JWT配置
    pub jwt: JwtConfig,
    /// 日志配置
    pub log: LogConfig,
    /// RPC配置
    pub rpc: RpcConfig,
    /// Nacos配置
    pub nacos: Option<NacosConfig>,
}

/// 服务器配置
#[derive(Debug, Deserialize, Clone)]
pub struct ServerConfig {
    /// 环境：dev 或 release
    pub env: String,
    /// 服务器名称
    pub name: String,
    /// 服务器地址
    pub address: String,
    /// 服务器端口
    pub port: u16,
    /// 是否启用SSL
    pub ssl: bool,
    /// 是否启用gzip压缩
    pub content_gzip: bool,
    /// 缓存时间（秒）
    pub cache_time: u64,
    /// 缓存方式
    pub cache_method: u32,
    /// API前缀，例如："/api/v1"
    pub api_prefix: String,
}

/// 数据库配置
#[derive(Debug, Deserialize, Clone)]
pub struct DatabaseConfig {
    /// 数据库连接字符串
    pub link: String,
    /// 最大连接数
    pub max_connections: Option<u32>,
    /// 最小连接数
    pub min_connections: Option<u32>,
    /// 连接超时时间（秒）
    pub connect_timeout: Option<u64>,
    /// 空闲超时时间（秒）
    pub idle_timeout: Option<u64>,
}

/// Redis配置
#[derive(Debug, Deserialize, Clone)]
pub struct RedisConfig {
    /// Redis服务器地址
    pub server: String,
    /// Redis密码
    pub password: String,
    /// 数据库编号
    pub db: i64,
    /// 端口
    pub port: u16,
    /// 连接池配置
    pub pool: Option<RedisPoolConfig>,
}

/// Redis连接池配置
#[derive(Debug, Deserialize, Clone)]
pub struct RedisPoolConfig {
    /// 最大连接数
    pub max_size: usize,
    /// 最小空闲连接数
    pub min_idle: usize,
    /// 连接超时时间（秒）
    pub connection_timeout: u64,
}

/// JWT配置
#[derive(Debug, Deserialize, Clone)]
pub struct JwtConfig {
    /// 访问令牌密钥
    pub access_secret: String,
    /// 访问令牌过期时间（秒）
    pub access_exp: i64,
    /// 刷新令牌密钥
    pub refresh_secret: String,
    /// 刷新令牌过期时间（秒）
    pub refresh_exp: i64,
}

/// 日志配置
#[derive(Debug, Deserialize, Clone)]
pub struct LogConfig {
    /// 日志级别
    pub log_level: String,
    /// 是否启用操作日志
    pub enable_oper_log: bool,
    /// 是否高亮显示
    pub with_ansi: bool,
    /// 是否输出到标准输出
    pub to_stdout: bool,
    /// 日志文件目录
    pub directory: String,
    /// 日志文件名
    pub file_name: String,
    /// 日志轮转方式
    pub rolling: String,
}

/// Nacos配置
#[derive(Debug, Deserialize, Clone)]
pub struct NacosConfig {
    /// Nacos服务器地址
    pub server_urls: String,
    /// 命名空间
    pub namespace: String,
    /// 用户名
    pub username: Option<String>,
    /// 密码
    pub password: Option<String>,
    /// 数据ID
    pub data_id: String,
    /// 组
    pub group: String,
}

impl Default for ServerConfig {
    fn default() -> Self {
        Self {
            env: "dev".to_string(),
            name: "app-server".to_string(),
            address: "0.0.0.0".to_string(),
            port: 8080,
            ssl: false,
            content_gzip: true,
            cache_time: 3600,
            cache_method: 1,
            api_prefix: "/api/v1".to_string(),
        }
    }
}

impl Default for DatabaseConfig {
    fn default() -> Self {
        Self {
            link: "postgres://user:password@localhost:5432/database".to_string(),
            max_connections: Some(10),
            min_connections: Some(2),
            connect_timeout: Some(30),
            idle_timeout: Some(300),
        }
    }
}

impl Default for RedisConfig {
    fn default() -> Self {
        Self {
            server: "127.0.0.1".to_string(),
            password: "".to_string(),
            db: 0,
            port: 6379,
            pool: Some(RedisPoolConfig::default()),
        }
    }
}

impl Default for RedisPoolConfig {
    fn default() -> Self {
        Self {
            max_size: 10,
            min_idle: 2,
            connection_timeout: 10,
        }
    }
}

impl Default for JwtConfig {
    fn default() -> Self {
        Self {
            access_secret: "your-access-secret-key".to_string(),
            access_exp: 3600, // 1小时
            refresh_secret: "your-refresh-secret-key".to_string(),
            refresh_exp: 86400 * 7, // 7天
        }
    }
}

impl Default for LogConfig {
    fn default() -> Self {
        Self {
            log_level: "info".to_string(),
            enable_oper_log: true,
            with_ansi: true,
            to_stdout: true,
            directory: "./logs".to_string(),
            file_name: "app.log".to_string(),
            rolling: "daily".to_string(),
        }
    }
}

/// 配置加载工具
pub struct ConfigLoader;

impl ConfigLoader {
    /// 从配置文件加载配置
    pub fn load_from_file<T>(config_path: &str) -> Result<T, Box<dyn std::error::Error>>
    where
        T: for<'de> Deserialize<'de>,
    {
        let config_content = std::fs::read_to_string(config_path)?;
        let config: T = if config_path.ends_with(".toml") {
            toml::from_str(&config_content)?
        } else if config_path.ends_with(".yaml") || config_path.ends_with(".yml") {
            serde_yaml::from_str(&config_content)?
        } else {
            serde_json::from_str(&config_content)?
        };
        Ok(config)
    }

    /// 从环境变量加载配置
    pub fn load_from_env<T>() -> Result<T, Box<dyn std::error::Error>>
    where
        T: for<'de> Deserialize<'de>,
    {
        let config = envy::from_env::<T>()?;
        Ok(config)
    }

    /// 合并配置（环境变量覆盖文件配置）
    pub fn load_merged<T>(config_path: &str) -> Result<T, Box<dyn std::error::Error>>
    where
        T: for<'de> Deserialize<'de> + Serialize,
    {
        // 先从文件加载
        let mut config: serde_json::Value = Self::load_from_file(config_path)?;
        
        // 然后从环境变量加载并合并
        if let Ok(env_config) = Self::load_from_env::<serde_json::Value>() {
            Self::merge_json(&mut config, env_config);
        }
        
        // 转换为目标类型
        let final_config: T = serde_json::from_value(config)?;
        Ok(final_config)
    }

    /// 合并JSON值
    fn merge_json(target: &mut serde_json::Value, source: serde_json::Value) {
        match (&mut *target, source) {
            (serde_json::Value::Object(target_map), serde_json::Value::Object(source_map)) => {
                for (key, value) in source_map {
                    if let Some(target_value) = target_map.get_mut(&key) {
                        Self::merge_json(target_value, value);
                    } else {
                        target_map.insert(key, value);
                    }
                }
            }
            (target_val, source_val) => {
                *target_val = source_val;
            }
        }
    }
}
